/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under 
 * the Apache License, Version 2.0  (the "License"); you may not use this file
 * except in compliance with the License.  
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */


#ifndef S6A_DEFS_H_
#define S6A_DEFS_H_

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include <freeDiameter/freeDiameter-host.h>
#include <freeDiameter/libfdcore.h>

#include "mme_config.h"
#include "queue.h"


#define VENDOR_3GPP (10415)
#define APP_S6A     (16777251)

/* Errors that fall within the Permanent Failures category shall be used to
 * inform the peer that the request has failed, and should not be attempted
 * again. The Result-Code AVP values defined in Diameter Base Protocol RFC 3588
 * shall be applied. When one of the result codes defined here is included in a
 * response, it shall be inside an Experimental-Result AVP and the Result-Code
 * AVP shall be absent.
 */
#define DIAMETER_ERROR_USER_UNKNOWN             (5001)
#define DIAMETER_ERROR_ROAMING_NOT_ALLOWED      (5004)
#define DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION (5420)
#define DIAMETER_ERROR_RAT_NOT_ALLOWED          (5421)
#define DIAMETER_ERROR_EQUIPMENT_UNKNOWN        (5422)
#define DIAMETER_ERROR_UNKOWN_SERVING_NODE      (5423)

/* Result codes that fall within the transient failures category shall be used
 * to inform a peer that the request could not be satisfied at the time it was
 * received, but may be able to satisfy the request in the future. The
 * Result-Code AVP values defined in Diameter Base Protocol RFC 3588 shall be
 * applied. When one of the result codes defined here is included in a response,
 * it shall be inside an Experimental-Result AVP and the Result-Code AVP shall
 * be absent.
 */
#define DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE (4181)

#define DIAMETER_ERROR_IS_VENDOR(x)                    \
   ((x == DIAMETER_ERROR_USER_UNKNOWN)              || \
    (x == DIAMETER_ERROR_ROAMING_NOT_ALLOWED)       || \
    (x == DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION)  || \
    (x == DIAMETER_ERROR_RAT_NOT_ALLOWED)           || \
    (x == DIAMETER_ERROR_EQUIPMENT_UNKNOWN)         || \
    (x == DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE) || \
    (x == DIAMETER_ERROR_UNKOWN_SERVING_NODE))

typedef struct {
  struct dict_object *dataobj_s6a_vendor;     /* s6a vendor object */
  struct dict_object *dataobj_s6a_app;        /* s6a application object */

  /* Commands */
  struct dict_object *dataobj_s6a_air; /* s6a authentication request */
  struct dict_object *dataobj_s6a_aia; /* s6a authentication answer */
  struct dict_object *dataobj_s6a_ulr; /* s6a update location request */
  struct dict_object *dataobj_s6a_ula; /* s6a update location asnwer */
  struct dict_object *dataobj_s6a_pur; /* s6a purge ue request */
  struct dict_object *dataobj_s6a_pua; /* s6a purge ue answer */
  struct dict_object *dataobj_s6a_clr; /* s6a Cancel Location req */
  struct dict_object *dataobj_s6a_cla; /* s6a Cancel Location ans */

  /* Some standard basic AVPs */
  struct dict_object *dataobj_s6a_destination_host;
  struct dict_object *dataobj_s6a_destination_realm;
  struct dict_object *dataobj_s6a_user_name;
  struct dict_object *dataobj_s6a_session_id;
  struct dict_object *dataobj_s6a_auth_session_state;
  struct dict_object *dataobj_s6a_result_code;
  struct dict_object *dataobj_s6a_experimental_result;

  /* S6A specific AVPs */
  struct dict_object *dataobj_s6a_visited_plmn_id;
  struct dict_object *dataobj_s6a_rat_type;
  struct dict_object *dataobj_s6a_ulr_flags;
  struct dict_object *dataobj_s6a_ula_flags;
  struct dict_object *dataobj_s6a_subscription_data;
  struct dict_object *dataobj_s6a_req_eutran_auth_info;
  struct dict_object *dataobj_s6a_number_of_requested_vectors;
  struct dict_object *dataobj_s6a_immediate_response_pref;
  struct dict_object *dataobj_s6a_authentication_info;
  struct dict_object *dataobj_s6a_re_synchronization_info;
  struct dict_object *dataobj_s6a_service_selection;
  struct dict_object *dataobj_s6a_ue_srvcc_cap;

  /* Handlers */
  struct disp_hdl *aia_hdl;   /* Authentication Information Answer Handle */
  struct disp_hdl *ula_hdl;   /* Update Location Answer Handle */
  struct disp_hdl *pua_hdl;   /* Purge UE Answer Handle */
  struct disp_hdl *clr_hdl;   /* Cancel Location Request Handle */
} s6a_fd_cnf_t;

extern s6a_fd_cnf_t s6a_fd_cnf;

#define ULR_SINGLE_REGISTRATION_IND      (1U)
#define ULR_S6A_S6D_INDICATOR            (1U << 1)
#define ULR_SKIP_SUBSCRIBER_DATA         (1U << 2)
#define ULR_GPRS_SUBSCRIPTION_DATA_IND   (1U << 3)
#define ULR_NODE_TYPE_IND                (1U << 4)
#define ULR_INITIAL_ATTACH_IND           (1U << 5)
#define ULR_PS_LCS_SUPPORTED_BY_UE       (1U << 6)

#define ULA_SEPARATION_IND          (1U)

#define FLAG_IS_SET(x, flag)   \
    ((x) & (flag))

#define FLAGS_SET(x, flags) \
    ((x) |= (flags))

#define FLAGS_CLEAR(x, flags)   \
    ((x) = (x) & ~(flags))

/* IANA defined IP address type */
#define IANA_IPV4   (0x1)
#define IANA_IPV6   (0x2)

#define AVP_CODE_VENDOR_ID                         (266)
#define AVP_CODE_EXPERIMENTAL_RESULT               (297)
#define AVP_CODE_EXPERIMENTAL_RESULT_CODE          (298)
#define AVP_CODE_SERVICE_SELECTION                 (493)
#define AVP_CODE_BANDWIDTH_UL                      (516)
#define AVP_CODE_BANDWIDTH_DL                      (515)
#define AVP_CODE_MSISDN                            (701)
#define AVP_CODE_SERVED_PARTY_IP_ADDRESS           (848)
#define AVP_CODE_QCI                               (1028)
#define AVP_CODE_ALLOCATION_RETENTION_PRIORITY     (1034)
#define AVP_CODE_PRIORITY_LEVEL                    (1046)
#define AVP_CODE_PRE_EMPTION_CAPABILITY            (1047)
#define AVP_CODE_PRE_EMPTION_VULNERABILITY         (1048)
#define AVP_CODE_SUBSCRIPTION_DATA                 (1400)
#define AVP_CODE_AUTHENTICATION_INFO               (1413)
#define AVP_CODE_E_UTRAN_VECTOR                    (1414)
#define AVP_CODE_NETWORK_ACCESS_MODE               (1417)
#define AVP_CODE_CONTEXT_IDENTIFIER                (1423)
#define AVP_CODE_SUBSCRIBER_STATUS                 (1424)
#define AVP_CODE_ACCESS_RESTRICTION_DATA           (1426)
#define AVP_CODE_ALL_APN_CONFIG_INC_IND            (1428)
#define AVP_CODE_APN_CONFIGURATION_PROFILE         (1429)
#define AVP_CODE_APN_CONFIGURATION                 (1430)
#define AVP_CODE_EPS_SUBSCRIBED_QOS_PROFILE        (1431)
#define AVP_CODE_AMBR                              (1435)
#define AVP_CODE_RAND                              (1447)
#define AVP_CODE_XRES                              (1448)
#define AVP_CODE_AUTN                              (1449)
#define AVP_CODE_KASME                             (1450)
#define AVP_CODE_PDN_TYPE                          (1456)
#define AVP_CODE_SUBSCRIBED_PERIODIC_RAU_TAU_TIMER (1619)

int s6a_init(const mme_config_t *mme_config);

int s6a_fd_new_peer(void);

void s6a_peer_connected_cb(struct peer_info *info, void *arg);

int s6a_fd_init_dict_objs(void);

int s6a_parse_subscription_data(struct avp *avp_subscription_data,
                                subscription_data_t *subscription_data);

int s6a_parse_experimental_result(struct avp *avp, s6a_experimental_result_t *ptr);
char *experimental_retcode_2_string(uint32_t ret_code);
char *retcode_2_string(uint32_t ret_code);


#endif /* S6A_DEFS_H_ */
